//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using Microsoft.Research.ScientificWorkflow.TridentModel;

    /// <summary>
    /// A collection of selected TridentUiElements.
    /// </summary>
    public class SelectedElementsCollection : ObservableCollection<ITridentUIElement>
    {
        private ITridentUIElement anchorElem;
        private ComposerRenderer composerRenderer;

        /// <summary>
        /// Collection of current trident elements.
        /// </summary>
        /// <param name="composerRenderer">
        /// The renderer.
        /// </param>
        public SelectedElementsCollection(ComposerRenderer composerRenderHelper)
        {
            if (null == composerRenderHelper)
            {
                throw new ArgumentNullException("composerRenderHelper");
            }

            this.composerRenderer = composerRenderHelper;
        }

        /// <summary>
        /// Gets if the collection contains only items of type subsection.
        /// </summary>
        public bool OnlySubsections
        {
            get
            {
                return this.Items.All(new Func<ITridentUIElement, bool>(this.CheckIfSubsection));
            }
        }

        /// <summary>
        /// Gets if the collection contains only items of type activity.
        /// </summary>
        public bool OnlyActivities
        {
            get
            {
                return this.Items.All(new Func<ITridentUIElement, bool>(this.CheckIfActivity));
            }
        }

        public bool OnlyActivitiesSupportingDelete
        {
            get
            {
                return this.Items.All(new Func<ITridentUIElement, bool>(this.CheckIfActivitySupportsDelete));
            }
        }

        /// <summary>
        /// Gets the collection which contains only menu items supported for activity.
        /// For example, simple activities or IfCondition.
        /// </summary>
        public bool OnlyActivitiesSupportingMenuItems
        {
            get
            {
                return this.Items.All(new Func<ITridentUIElement, bool>(this.CheckIfParamSupportingActivity));
            }
        }

        /// <summary>
        /// Selects the elements upto the passed element.
        /// </summary>
        /// <param name="lastElem">
        /// The last element to be selected in the series.
        /// </param>
        public void SelectChildrenUpTo(ITridentUIElement lastElement)
        {
            int firstIndex = -1;
            int lastIndex = -1;
            ICompositeUIElement parentElement = null;

            if (this.composerRenderer.CurrentComposerCtrl != null && 
                (this.composerRenderer.CurrentComposerCtrl.CurrentRenderMode == RenderMode.MonitorMode ||
                 this.composerRenderer.CurrentComposerCtrl.CurrentRenderMode == RenderMode.ProvenanceMode ||
                 this.composerRenderer.CurrentComposerCtrl.CurrentRenderMode == RenderMode.VisualizationMode))
            {
                this.RemoveAllItems();
            }

            if (null == this.anchorElem)
            {
                this.anchorElem = lastElement;
                this.AddElement(lastElement);
            }
            else if (this.ValidSelection(lastElement, out parentElement, out firstIndex, out lastIndex))
            {
                if (parentElement != null && firstIndex > -1 && lastIndex > -1)
                {
                    this.ResetCollection();
                    for (int index = firstIndex; index <= lastIndex; index++)
                    {
                        this.AddElement(parentElement.ChildElements[index]);
                    }
                }
            }
        }

        /// <summary>
        /// Removes all the items.
        /// </summary>
        public void RemoveAllItems()
        {
            this.anchorElem = null;
            this.ResetCollection();
        }

        private void ApplyUnselectedStyle()
        {
            foreach (ITridentUIElement elem in this.Items)
            {
                elem.ApplyUnselectedStyle();
            }
        }

        private void AddElement(ITridentUIElement tridentElem)
        {
            if (tridentElem != null)
            {
                this.Add(tridentElem);
                tridentElem.ApplySelectedStyle();
            }
        }

        private void ResetCollection()
        {
            this.ApplyUnselectedStyle();
            this.Clear();
        }

        private bool ValidSelection(ITridentUIElement lastElem, out ICompositeUIElement parentElem, out int firstIndex, out int lastIndex)
        {
            bool allValid = false;
            firstIndex = -1;
            lastIndex = -1;
            parentElem = null;

            if (lastElem != null)
            {
                if (anchorElem != null)
                {
                    if (anchorElem.Model.ParentModel != null && lastElem.Model.ParentModel != null
                        && this.composerRenderer.UIElements.ContainsKey(anchorElem.Model.ParentModel.UniqueId)
                        && this.composerRenderer.UIElements.ContainsKey(lastElem.Model.ParentModel.UniqueId))
                    {
                        ITridentUIElement anchorParentElem = this.composerRenderer.UIElements[anchorElem.Model.ParentModel.UniqueId];
                        ITridentUIElement lastParentElem = this.composerRenderer.UIElements[lastElem.Model.ParentModel.UniqueId];
                        if (anchorParentElem != null && lastParentElem != null && anchorParentElem.Equals(lastParentElem))
                        {
                            parentElem = anchorParentElem as ICompositeUIElement;
                            if (parentElem != null)
                            {
                                int anchorIndex = parentElem.ChildElements.IndexOf(anchorElem);
                                int lastElemIndex = parentElem.ChildElements.IndexOf(lastElem);
                                if (anchorIndex <= lastElemIndex)
                                {
                                    firstIndex = anchorIndex;
                                    lastIndex = lastElemIndex;
                                }
                                else
                                {
                                    firstIndex = lastElemIndex;
                                    lastIndex = anchorIndex;
                                }

                                allValid = true;
                            }
                            
                        }
                    }
                }
                else
                {
                    allValid = true;
                    firstIndex = 0;
                    lastIndex = 0;
                }
            }

            return allValid;
        }
        
        private bool CheckIfSubsection(ITridentUIElement elem)
        {
            return elem is ISubsectionControl;
        }

        private bool CheckIfActivity(ITridentUIElement elem)
        {
            return elem is TridentUIActivityElement;
        }

        private bool CheckIfParamSupportingActivity(ITridentUIElement elem)
        {
            bool valid = false;
            CompositeActivityModel condition = elem.Model as CompositeActivityModel;
            if (elem is WorkflowActivityElement || (condition != null 
                && condition.ActivityClass.Equals("TridentBasicActivities.Activities.IfCondition", StringComparison.CurrentCulture)))
            {
                valid = true;
            }

            return valid;
        }

        private bool CheckIfActivitySupportsDelete(ITridentUIElement elem)
        {
            bool valid = false;
            valid = (elem.Model.DeleteBehavior != ActivityDeleteBehavior.DeleteInvalid);

            return valid;

        }
    }
}
